<template>
  <n-card :bordered="false" class="proCard">
    <BasicForm
      ref="bfref"
      @register="register"
      @submit="handleSubmit">
      <template #statusSlot="{ model, field }">
        <n-input v-model:value="model[field]"/>
      </template>
    </BasicForm>

    <BasicTable
      :columns="columns"
      :dataSource="procdata.data"
      :row-key="(row) => row.id"
      :actionColumn="actionColumn"
      :scroll-x="1090"
    >
      <template #tableTitle>
        <n-button type="primary" @click="addTable" size="small">
          <template #icon>
            <n-icon>
              <PlusOutlined/>
            </n-icon>
          </template>
          新建
        </n-button>
        <n-button type="error" @click="reloadStatus" size="small">
          <template #icon>
            <n-icon>
              <ReloadOutlined/>
            </n-icon>
          </template>
          重载状态
        </n-button>
      </template>
    </BasicTable>
    <!--添加任务-->
    <n-modal v-model:show="showModal" :show-icon="false" preset="card" size="small"
             style="width: 80%"
             title="添加任务">
      <n-form
        :model="formParams"
        :rules="addrules"
        ref="formRef"
        label-placement="left"
        :label-width="150"
        class="py-4"
      >
        <n-form-item label="任务描述" path="desc">
          <n-input
            placeholder="请输入完整的任务描述" v-model:value="formParams.desc"/>
        </n-form-item>
        <n-form-item label="任务路径" path="name">
          <n-input :disabled="formParams.id>0"
                   placeholder="请输入完整的绝对路径" v-model:value="formParams.name"/>
        </n-form-item>

        <n-form-item label="自定义日志目录" path="log">
          <n-input placeholder="请自定义日志目录,留空则使用系统设置"
                   v-model:value="formParams.log"/>
        </n-form-item>
        <n-form-item label="更新包存储路径" path="upload_dir">
          <n-input placeholder="请更新包存储路径" v-model:value="formParams.upload_dir"/>
        </n-form-item>
        <n-form-item label="更新包解压路径" path="ext_to_dir">
          <n-input placeholder="请更新包解压路径" v-model:value="formParams.ext_to_dir"/>
        </n-form-item>
        <n-form-item label="更新包上传前操作" path="beforce">
          <n-input placeholder="更新包上传前操作" v-model:value="formParams.beforce"
                   type="textarea"/>
        </n-form-item>
        <n-form-item label="更新包上传后操作" path="after">
          <n-input placeholder="更新包上传后操作" v-model:value="formParams.after" type="textarea"/>
        </n-form-item>
        <n-grid x-gap="12" :cols="2">
          <n-gi>
            <n-form-item label="启动用户" path="user">
              <n-input placeholder="请启动用户" v-model:value="formParams.user"/>
            </n-form-item>
          </n-gi>
          <n-gi>
            <n-form-item label="启动参数" path="args">
              <n-input placeholder="请启动参数" v-model:value="formParams.args"/>
            </n-form-item>
          </n-gi>
        </n-grid>
        <n-grid x-gap="12" :cols="3">
          <n-gi>
            <n-form-item label="不自动重启" path="no_auto_restart">
              <n-switch v-model:value="formParams.no_auto_restart"/>
            </n-form-item>
          </n-gi>
          <n-gi>
            <n-form-item label="服务器端解压" path="sys_ctr">
              <n-switch v-model:value="formParams.sys_ctr"/>
            </n-form-item>
          </n-gi>
          <n-gi>
            <n-form-item label="服务器端编译" path="sys_build">
              <n-switch v-model:value="formParams.sys_build"/>
            </n-form-item>
          </n-gi>
        </n-grid>
      </n-form>

      <template #action>
        <n-space>
          <n-button @click="() => (showModal = false)">取消</n-button>
          <n-button type="info" :loading="formBtnLoading" @click="confirmForm">确定</n-button>
        </n-space>
      </template>
    </n-modal>
    <!--    更新服务-->
    <n-modal v-model:show="upgradeModal" :show-icon="false" preset="card" size="small"
             style="width: 80%"
             title="升级服务">
      <n-form
        :model="upgradeParams"
        :rules="upgradeRules"
        ref="upgradeRef"
        label-placement="left"
        :label-width="150"
        class="py-4"
      >
        <n-form-item label="任务描述" path="desc">
          <n-input disabled
                   placeholder="请输入完整的绝对路径" v-model:value="formParams.desc"/>
        </n-form-item>
        <n-form-item label="任务路径" path="name">
          <n-input :disabled="true"
                   placeholder="请输入完整的绝对路径" v-model:value="upgradeParams.name"/>
        </n-form-item>
        <n-form-item label="更新包存储路径" path="upload_dir">
          <n-input placeholder="请更新包存储路径" v-model:value="upgradeParams.upload_dir"/>
        </n-form-item>
        <n-form-item label="更新包解压路径" path="ext_to_dir">
          <n-input placeholder="请更新包解压路径" v-model:value="upgradeParams.ext_to_dir"/>
        </n-form-item>
        <n-form-item label="更新包上传前操作" path="beforce">
          <n-input placeholder="更新包上传前操作" v-model:value="upgradeParams.beforce"
                   type="textarea"/>
        </n-form-item>
        <n-form-item label="更新包上传后操作" path="after">
          <n-input placeholder="更新包上传后操作" v-model:value="upgradeParams.after"
                   type="textarea"/>
        </n-form-item>
        <n-grid x-gap="12" :cols="2">
          <n-gi>
            <n-form-item label="服务器端解压" path="sys_ctr">
              <n-switch v-model:value="upgradeParams.sys_ctr"/>
            </n-form-item>

          </n-gi>
          <n-gi>
            <n-form-item label="服务器端编译" path="sys_build">
              <n-switch v-model:value="upgradeParams.sys_build"/>
            </n-form-item>
          </n-gi>
        </n-grid>
        <n-form-item label="选择升级包" path="after">
          <n-upload
            ref="uploadRef"
            :headers="{'Authorization':userToken}"
            :action="apiUrl"
            :default-upload="false"
            @change="uploadChange"
            accept=".zip,.7z"
            @before-upload="beforeUpload"
            :data="upgradeParams"
            :multiple="false"
            :on-finish="upFinish"
            :on-error="upError"
          >
            <n-button>选择文件</n-button>
          </n-upload>
        </n-form-item>

      </n-form>

      <template #action>
        <n-space>
          <n-button @click="() => (upgradeModal = false)">取消</n-button>
          <n-button :disabled="!fileListLengthRef" type="info" :loading="upBtnLoading"
                    @click="doUpgrade">确定
          </n-button>
        </n-space>
      </template>
    </n-modal>
  </n-card>
</template>

<script lang="ts" setup>
import {h, onBeforeMount, reactive, ref} from 'vue';
// import { useMessage } from 'naive-ui';
import {BasicTable, TableAction} from '@/components/Table';
import {BasicForm, FormSchema, useForm} from '@/components/Form/index';
import {PlusOutlined,ReloadOutlined} from '@vicons/antd';
import {http} from "@/utils/http/axios";
import {FormInst, NSwitch, UploadFileInfo, UploadInst, useDialog} from "naive-ui";
import {useUserStore} from "@/store/modules/user";
import {useGlobSetting} from "@/hooks/setting";

const bfref = ref();
const procdata = reactive({
  data: []
})
const fileListLengthRef = ref(0)
let uploadRef = ref<UploadInst | null>(null);
let formParams = newFormParams();
let showModal = ref(false);
let formBtnLoading = ref(false);
const formRef = ref<FormInst | null>()
let upgradeRef: any = ref(null)

function uploadChange(options: { fileList: UploadFileInfo[] }) {
  fileListLengthRef.value = options.fileList.length
}

const userToken = useUserStore().getUserInfo["token"];
const apiUrl = useGlobSetting().apiUrl + '/api/upload';

function beforeUpload(data: {
  file: UploadFileInfo
  fileList: UploadFileInfo[]
}) {
  if (data.file?.type.indexOf("zip") < 0 && data.filefile?.type.indexOf("7z") < 0) {
    window['$message'].success('新建成功').error("只能上传7z或zip包");
    return false
  }
  return true
}

function upError(options) {
  window["$message"].error(options.event.target.response);
}

const dialog = useDialog();

function upFinish({file, event}: { file: UploadFileInfo, event?: ProgressEvent }) {
  console.log(event)
  upBtnLoading.value = false;
  upgradeModal.value = false;
  if (event == null || event.target == null || event.target.response == null) {
    dialog.success({
      title: '完成',
      content: "未返回response对像,请观察pid是否有更新确认是否更新成功",
      positiveText: '知道了',

    });
    return;
  }
  const response = (event?.target as XMLHttpRequest).response;
  let rtn = JSON.parse(response)
  loadDataTable(bfref.value.formModel)
  dialog.success({
    title: '成功',
    content: rtn.result.cmdrtn.join("\n").replaceAll("", ""),
    positiveText: '知道了',

  })
  // alert(rtn.result["cmdrtn"].join(""))
}

function doUpgrade() {
  upBtnLoading.value = true
  uploadRef.value?.submit()
}

function confirmForm(e) {
  e.preventDefault();
  if (formBtnLoading.value === false) {
    formRef.value?.validate((errors) => {
      if (!errors) {
        formBtnLoading.value = true;
        http.request({
          url: "/api/add",
          method: "post",
          data: formParams,
        }).then((res) => {
          loadDataTable(bfref.value.formModel)
          window['$message'].success('成功');
          formParams = newFormParams();
          showModal.value = false;
          formBtnLoading.value = false;
        }).catch((err) => {
          const message = err.message ?? err
          window['$message'].error(message);
          showModal.value = false;
          formBtnLoading.value = false;
        })
      } else {
        window['$message'].error('请填写完整信息');
      }
    });
  }

}

function addTable() {
  formParams = newFormParams();
  showModal.value = true;
}
function reloadStatus(){
  formBtnLoading.value = true;
  http.request({
    url: "/api/reload_status"
  }).then(() => {
    window['$message'].info("成功")
    loadDataTable(bfref.value.formModel)
  }).catch((err)=>{
    const message = err.message ?? err
    window['$message'].error(message);
  }).finally(()=>{
    formBtnLoading.value = false;
  })
}

//新增的model
function newFormParams() {
  return reactive({
    id: 0,
    name: '',//文件
    user: 'root',//启动用户
    no_auto_restart: true,//自动重启
    args: "",//启动参数
    log: "",//自定义日志目录
    sys_ctr: false,//服务器端解压,
    sys_build: true,//系统控制编译
    upload_dir: '',//更新包存储路径
    ext_to_dir: '',//更新包解压目的路径
    beforce: '',//更新包上传前操作
    after: '',//更新包上传后操作
    desc: '',

  });
}

function openEdit(rowData: object, colName: string) {
  return h("a", {
    id: rowData["id"],
    onClick: (e) => {
      http.request({
        url: "/api/edit/" + e.target.id
      }).then((res) => {
        formParams = Object.assign(newFormParams(), reactive(res));
        formParams.name = res.process_file;
        formParams.desc = res.desc;
        formParams.no_auto_restart = !res.auto_restart
        showModal.value = true;
        formBtnLoading.value = false;
      }).catch((error) => {
        const message = error.message ?? error
        window['$message'].error(message);
      })
    }
  }, [rowData[colName]])
}

const columns = [
  {
    title: 'id',
    key: 'id',
    width: 50,
    render: (rowData: object) => {
      return openEdit(rowData, "id");
    }
  },
  {
    title: '进程文件',
    key: 'process_file',
    width: 200,
    render: (rowData: object) => {
      return openEdit(rowData, "process_file")
    }
  },
  {
    title: 'PID',
    key: 'pid',
    width: 75,
  },
  {
    title: '运行用户',
    key: 'Username',
    width: 100,
  },
  {
    title: '自动重启',
    key: 'auto_restart',
    width: 75,
    render: (rowData: object) => {
      return rowData.auto_restart ? "是" : "否";
    }
  },
  {
    title: '创建日期',
    key: 'created_at',
    width: 75,
    render: (rowData: object) => {
      return h("span", [rowData["created_at"].substring(0, 10)])
    },

  },
  {
    title: '状态',
    key: 'status',
    width: 75,
    render: (rowData: object) => {
      let statustxt = rowData["status"]
      switch (rowData["status"]) {
        case "init":
          statustxt = "正在初始化";
          break;
        case "running":
          statustxt = "运行中";
          break;
        case "stopped":
          statustxt = "已停止";
          break;
        case "reload":
          statustxt = "重载入中";
          break;
        case "failed":
          statustxt = "异常";
          break;
      }
      return h("span", [statustxt])
    },

  },
  // StatusInit    = "init"    // init process
  // StatusRunning = "running" // success running
  // StatusStopped = "stopped" // success finished or run stop success
  // StatusReload  = "reload"  //
  // StatusFailed  = "failed"  // run error
];
let disbtn = ref(false)
//行中操作按钮
const actionColumn = reactive({
  width: 220,
  title: '操作',
  key: 'action',
  fixed: 'right',
  render(record, rowIdx) {
    return h(TableAction as any, {
      style: 'button',
      actions: [
        {
          label: record.status == "running" ? "运行中" : "启动",
          onClick: handleStart.bind(null, record),
          // 根据业务控制是否显示 isShow 和 auth 是并且关系
          ifShow: () => {
            return true;
          },
          disabled: record.status == "running" || disbtn.value,
        },
        {
          label: '停止',
          onClick: handleStop.bind(null, record),
          disabled: record.status == "stopped" || disbtn.value
        },
        {
          label: '重启',
          key: 'restart',
          disabled: disbtn.value,
          onClick: handleRestart.bind(null, record),
        },
        {
          label: '删除',
          key: 'del',
          disabled: disbtn.value,
          onClick: handleDel.bind(null, {record, rowIdx}),
        },
        {
          label: '升级',
          key: 'upgrade',
          disabled: disbtn.value,
          onClick: openUpgrade.bind(null, record),
        },
      ],
    });
  },
});

function openUpgrade(record: Recordable) {
  http.request({
    url: "/api/edit/" + record["id"]
  }).then((res) => {
    upgradeParams = Object.assign(newUpgradeParams(), reactive(res));
    upgradeParams.name = res.process_file;
    upgradeParams.desc = res.name;
    upgradeParams.no_auto_restart = !res.auto_restart
    fileListLengthRef.value = 0;
    upgradeModal.value = true;
    upBtnLoading.value = false;
  }).catch((error) => {
    const message = error.message ?? error
    window['$message'].error(message);
  })
}

function handleStart(record: Recordable) {
  disbtn.value = true;
  http.request({
    url: "/api/start/" + record.id,
    method: "get",
  }).then((res) => {
    record.status = res?.status ?? "";
    record.pid = res?.pid ?? "";
    disbtn.value = false;
    window['$message'].info(`已启动`);
  }).catch((err) => {
    const message = err.message ?? err
    window['$message'].error(message);
    disbtn.value = false;
  })
}

let force = ref(true)

function handleStop(record: Recordable) {
  window['$dialog'].warning({
    title: '确认停止',
    positiveText: '确定',
    negativeText: '取消',
    content: () => {
      return h("span", ["强制停止:", h(NSwitch, {
        defaultValue: force,
        onUpdateValue: (v) => {
          force.value = v
        }
      })])
    },
    onPositiveClick: () => {
      disbtn.value = true;
      http.request({
        url: "/api/stop/" + record.id,
        method: "get",
        params: {
          "force": force.value
        }
      }).then(() => {
        record.status = "stopped";
        record.pid = 0;
        window['$message'].info(`已停止`);
        disbtn.value = false;
      }).catch((err) => {
        const message = err.message ?? err
        window['$message'].error(message);
        disbtn.value = false;
      })
    }
  })

}

function handleRestart(record: Recordable) {
  disbtn.value = true;
  http.request({
    url: "/api/restart/" + record.id,
    method: "get",
  }).then((res) => {
    record.status = res.status;
    record.pid = res.pid;
    window['$message'].info(`已重启`);
    disbtn.value = false;
  }).catch((err) => {
    const message = err.message ?? err
    window['$message'].error(message);
    disbtn.value = false;
  })
}

function handleDel(rowObj) {
  const rowIdx = rowObj.rowIdx;
  const record = rowObj.record
  window['$dialog'].warning({
    title: '确认删除',
    content: '你确定？',
    positiveText: '确定',
    negativeText: '取消',
    onPositiveClick: () => {
      disbtn.value = true;
      http.request({
        url: "/api/del/" + record.id,
        method: "get",
      }).then(() => {
        window['$message'].info(`已删除`);
        disbtn.value = false;
        procdata.data.splice(rowIdx, 1)
      }).catch((err) => {
        const message = err.message ?? err
        window['$message'].error(message);
        disbtn.value = false;
      })
    }
  })


}

function newUpgradeParams() {
  let p = newFormParams();
  p = Object.assign(p, reactive({
    files: []
  }));
  return p
}

//加载数据
const loadDataTable = (queryObj) => {
  http.request({
    url: "/api/list?",
    method: "get",
    params: queryObj

  }).then((res) => {
    procdata.data = res
  })
};

let upgradeModal = ref(false)
let upBtnLoading = ref(false)
let upgradeParams = newUpgradeParams();

//新增的规则
const addrules = {
  desc: {
    required: true,
    trigger: ['blur', 'input'],
    message: '请输入任务描述',
  },
  name: {
    required: true,
    trigger: ['blur', 'input'],
    message: '请输入任务路径',
  },
  user: {
    required: true,
    trigger: ['blur', 'input'],
    message: '请输入启动用户',
  },
  upload_dir: {
    required: true,
    trigger: ['blur', 'input'],
    message: '请输入更新包存储路径',
  },
  ext_to_dir: {
    required: true,
    trigger: ['blur', 'input'],
    message: '请输入更新包存储路径',
  },
};
//升级包规则
let upgradeRules = {
  files: {
    required: true,
    trigger: ['blur', 'input'],
    message: '请上传文件',
  },
}
//查询的配置
const schemas: FormSchema[] = [
  {
    field: 'name',
    component: 'NInput',
    label: '进程名',
    componentProps: {
      placeholder: '请输入进程名称',
    },
  },
];
//查询form的宽度配置
const [register, {}] = useForm({
  gridProps: {cols: '1 s:1 m:2 l:3 xl:4 2xl:4'},
  labelWidth: 80,
  schemas,
});
onBeforeMount(() => {
  loadDataTable({});
})

function handleSubmit(values: Recordable) {
  loadDataTable(values)
}


</script>

<style lang="less" scoped></style>
